<template>
  <div class="container">
    <p ref="offscreenText" class="offscreen-text"></p>
    <p ref="text" class="text"></p>
    <svg ref="svg" :viewBox="viewBox"></svg>
    <input
      ref="input"
      v-model="inputValue"
      class="input"
      @keyup="handleKeyUp"
    />
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { gsap } from 'gsap'

// 定义颜色数组
const colors = [
  { main: '#FBDB4A', shades: ['#FAE073', '#FCE790', '#FADD65', '#E4C650'] },
  { main: '#F3934A', shades: ['#F7B989', '#F9CDAA', '#DD8644', '#F39C59'] },
  { main: '#EB547D', shades: ['#EE7293', '#F191AB', '#D64D72', '#C04567'] },
  { main: '#9F6AA7', shades: ['#B084B6', '#C19FC7', '#916198', '#82588A'] },
  { main: '#5476B3', shades: ['#6382B9', '#829BC7', '#4D6CA3', '#3E5782'] },
  { main: '#2BB19B', shades: ['#4DBFAD', '#73CDBF', '#27A18D', '#1F8171'] },
  { main: '#70B984', shades: ['#7FBE90', '#98CBA6', '#68A87A', '#5E976E'] }
]

// 定义 ref 变量
const svg = ref(null)
const text = ref(null)
const offscreenText = ref(null)
const input = ref(null)
const inputValue = ref('')
const letters = reactive([])
const viewBox = ref('0 0 0 0')
const runPrompt = ref(true)

// 定义提示文字
const prompt = ['每','一','步','都','是','进','步','，','前','进','吧','！']

// 定义窗口宽高和文字大小
let width = ref(window.innerWidth)
let height = ref(window.innerHeight)
let textSize = ref(0)
let textCenter = ref(0)

// 定义 SVG 元素包装类
class SVGElementWrapper {
  constructor(element) {
    this.element = element
  }

  set(attributeName, value) {
    this.element.setAttribute(attributeName, value)
  }

  style(property, value) {
    this.element.style[property] = value
  }
}

// 创建 SVG 元素
const createSVGElement = (type) => {
  const el = document.createElementNS('http://www.w3.org/2000/svg', type)
  return new SVGElementWrapper(el)
}

// 窗口大小改变时，重新计算宽高和 viewBox
const resizePage = () => {
  width.value = window.innerWidth
  height.value = window.innerHeight
  viewBox.value = `0 0 ${width.value} ${height.value}`
  resizeLetters()
}

// 重新计算文字大小和位置
const resizeLetters = async () => {
  textSize.value = Math.min(width.value / (letters.length + 8), 100)
  text.value.style.fontSize = `${textSize.value}px`
  text.value.style.height = `${textSize.value}px`
  text.value.style.lineHeight = `${textSize.value}px`
  offscreenText.value.style.fontSize = `${textSize.value}px`
  
  await nextTick()
  const textRect = text.value.getBoundingClientRect()
  textCenter.value = textRect.top + textRect.height / 2
  positionLetters()
}

// 重新计算字母位置
const positionLetters = () => {
  letters.forEach((letter) => {
    const timing = letter.shift ? 0.1 : 0
    gsap.to(letter.onScreen, {
      x: `${letter.offScreen.offsetLeft}px`*0.2,
      duration: timing,
      ease: 'power3.inOut'
    })
    letter.shift = true
  })
}

// 动画字母进入
const animateLetterIn = (letter) => {
  const yOffset = (0.5 + Math.random() * 0.5) * textSize.value
    // 确保目标元素应用了 transform 属性
  gsap.set(letter, {
    transformOrigin: 'center center',
    display: 'inline-block'  // 添加 display 属性保证 transform 生效
  })
  // 分开处理不同属性的动画
  gsap.fromTo(letter,
    { 
      scale: 0,
      opacity: 0,
      rotation: -50 + Math.random() * 100,
      y: -yOffset
    },
    { 
      scale: 1,
      opacity: 1,
      duration: 0.4,
      ease: 'back.out(1.7)',
      rotation: 0,
      y: 0,
      onComplete: () => {
        // 添加弹性动画增强跳动感
        gsap.to(letter, {
          y: -yOffset * 0.3,
          duration: 0.15,
          repeat: 1,
          yoyo: true,
          ease: 'power2.inOut'
        })
      }
    }
  )
  gsap.to(letter, {
    y: -yOffset,
    duration: 0.2,
    ease: 'power3.inOut'
  })
  gsap.to(letter, {
    y: 0,
    duration: 0.2,
    delay: 0.2,
    ease: 'power3.inOut'
  })
  
  const rotation = -50 + Math.random() * 100
  gsap.to(letter, {
    rotation,
    duration: 0.2,
    ease: 'power3.inOut'
  })
  gsap.to(letter, {
    rotation: 0,
    duration: 0.2,
    delay: 0.2,
    ease: 'power3.inOut'
  })
}

// 添加装饰
const addDecor = (letter, color) => {
  setTimeout(() => {
    const rect = letter.getBoundingClientRect()
    const x0 = letter.offsetLeft + letter.offsetWidth *1.8
    const y0 = textCenter.value - textSize.value * 0.5
    const shade = color.shades[Math.floor(Math.random() * 4)]
    
    for (let i = 0; i < 8; i++) addTri(x0, y0, shade)
    for (let i = 0; i < 8; i++) addCirc(x0, y0)
  }, 150)
}

// 添加三角形
const addTri = (x0, y0, shade) => {
  const tri = createSVGElement('polygon')
  const a = Math.random()
  const a2 = a + (-0.2 + Math.random() * 0.4)
  const r = textSize.value * 0.52
  const r2 = r + textSize.value * Math.random() * 0.2
  const x = x0 + r * Math.cos(2 * Math.PI * a)
  const y = y0 + r * Math.sin(2 * Math.PI * a)
  const x2 = x0 + r2 * Math.cos(2 * Math.PI * a2)
  const y2 = y0 + r2 * Math.sin(2 * Math.PI * a2)
  const triSize = textSize.value * 0.1
  const scale = 0.3 + Math.random() * 0.7
  const offset = triSize * scale

  tri.set('points', `0,0 ${triSize * 2},0 ${triSize},${triSize * 2}`)
  tri.style('fill', shade)
  svg.value.appendChild(tri.element)

  gsap.fromTo(tri.element,
    { rotation: Math.random() * 360, scale, x: x - offset, y: y - offset, opacity: 1 },
    {
      x: x2 - offset,
      y: y2 - offset,
      opacity: 0,
      duration: 0.6,
      ease: 'power1.inOut',
      onComplete: () => svg.value.removeChild(tri.element)
    }
  )
}

// 添加圆形
const addCirc = (x0, y0) => {
  const circ = createSVGElement('circle')
  const a = Math.random()
  const r = textSize.value * 0.52
  const r2 = r + textSize.value
  const x = x0 + r * Math.cos(2 * Math.PI * a)
  const y = y0 + r * Math.sin(2 * Math.PI * a)
  const x2 = x0 + r2 * Math.cos(2 * Math.PI * a)
  const y2 = y0 + r2 * Math.sin(2 * Math.PI * a)
  const circSize = textSize.value * 0.05 * Math.random()

  circ.set('r', circSize)
  circ.style('fill', '#eee')
  svg.value.appendChild(circ.element)

  gsap.fromTo(circ.element,
    { x: x - circSize, y: y - circSize, opacity: 1 },
    {
      x: x2 - circSize,
      y: y2 - circSize,
      opacity: 0,
      duration: 0.6,
      ease: 'power1.inOut',
      onComplete: () => svg.value.removeChild(circ.element)
    }
  )
}

// 添加字母
const addLetter = (char, index) => {
  const letter = document.createElement('span')
  const oLetter = document.createElement('span')
  letter.textContent = char
  oLetter.textContent = char
  
  text.value.appendChild(letter)
  offscreenText.value.appendChild(oLetter)
  
  const color = colors[index % colors.length]
  letter.style.color = color.main

  const newLetter = {
    offScreen: oLetter,
    onScreen: letter,
    char,
    shift: false
  }
  
  letters.push(newLetter)
  animateLetterIn(letter)
  addDecor(oLetter, color)
}

// 处理输入变化
const handleInputChange = () => {
  const value = inputValue.value.toLowerCase().split('')

  // Add new letters
  value.forEach((char, index) => {
    if (!letters[index] || letters[index].char !== char) {
      if (letters[index]) {
        letters[index].onScreen.textContent = char
        letters[index].offScreen.textContent = char
        letters[index].char = char
      } else {
        addLetter(char, index)
      }
    }
  })

  // Remove extra letters
  while (letters.length > value.length) {
    const letter = letters.pop()
    gsap.to(letter.onScreen, {
      scale: 0,
      opacity: 0,
      duration: 0.1,
      ease: 'power2.in',
      onComplete: () => {
        text.value.removeChild(letter.onScreen)
        offscreenText.value.removeChild(letter.offScreen)
        positionLetters()
      }
    })
  }

  resizeLetters()
}

const handleKeyUp = () => {
  if (runPrompt.value) {
    inputValue.value = ''
    runPrompt.value = false
  }
}

const addPrompt = (index) => {
  if (!runPrompt.value || !prompt[index]) return

  setTimeout(() => {
    inputValue.value += prompt[index]
    addPrompt(index + 1)
  }, 300)
}

onMounted(() => {
  window.addEventListener('resize', resizePage)
  resizePage()
  input.value.focus()
  addPrompt(0)
})

onUnmounted(() => {
  window.removeEventListener('resize', resizePage)
})

watch(inputValue, handleInputChange)
</script>

<style scoped>
.container {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.text {
  position: absolute;
  /* top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); */
  top:50%;
  margin: 0;
  white-space: nowrap;
}

.offscreen-text {
  position: absolute;
  visibility: hidden;
  white-space: nowrap;
  margin: 0;
}

.input {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  padding: 10px;
  border: none;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 4px;
  font-size: 16px;
  outline: none;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
</style>

